using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.Windows.Forms;
using ZoneFiveSoftware.Common.Data.Fitness;
using ZoneFiveSoftware.Common.Visuals;
using CheckedComboBox;
using FilteredStatistics.Common;
using FilteredStatistics.Common.Controller;
using FilteredStatistics.Controller;
using FilteredStatistics.Data;

namespace FilteredStatistics.View
{
    partial class FilterListControl : UserControl
    {
        public FilterListControl()
        {
            InitializeComponent();

            FilterCriteriaController.Instance.AvailableCriteriasChanged += new PropertyChangedEventHandler(OnAvailableCriteriasChanged);

            FiltersDataGridView.EnableHeadersVisualStyles = false;
            FiltersDataGridView.AutoGenerateColumns = false;
            FilterTypeColumn.ValueType = typeof(IFilterCriteria);
            FilterTypeColumn.DisplayMember = "DisplayName";

            SetupAvailableCriterias();

            ItemColumn.DataPropertyName = "Name";
        }

        void OnAvailableCriteriasChanged(object sender, PropertyChangedEventArgs e)
        {
            SetupAvailableCriterias();
        }

        private void OnFilterChanged(Filter filter, PropertyChangedEventArgs changedProperty)
        {
            CheckIfEmptyRowRequired();

            if (Filters.Contains(filter) && changedProperty.PropertyName != "ValidTimes")
            {
                RefreshDataGridViewFromFilters(Filters);
            }
        }

        private void OnFilterListChanged(FilterList filters, PropertyChangedEventArgs changedProperty)
        {
            RefreshDataGridViewFromFilters(Filters);
        }

        private void FiltersDataGridView_ColumnWidthChanged(object sender, DataGridViewColumnEventArgs e)
        {
            if (e.Column == FilterTypeColumn)
            {
                CriteriaTypesColumnWidth = FilterTypeColumn.Width;
            }
            else if (e.Column == ItemColumn)
            {
                NamedZonesColumnWidth = ItemColumn.Width;
            }
            else if (e.Column == RemoveFilterColumn)
            {
                e.Column.Width = 25;
            }
            else
            {
                TriggerColumnWidthChanged(sender, e);
            }
        }

        private void FiltersDataGridView_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
        {
            ComboBox childComboBox = e.Control as ComboBox;
            CheckedComboBoxControl childCheckComboBox = e.Control as CheckedComboBoxControl;

            // Put this before the ComboBox check because it derives from ComboBox
            if (childCheckComboBox != null)
            {
                childCheckComboBox.DropDownClosed += new EventHandler(FiltersDataGridView_DropDownClosed);
            }
            else if (childComboBox != null)
            {
                childComboBox.SelectedIndexChanged += new EventHandler(FiltersDataGridView_ComboBoxSelectedIndexChanged);
            }
        }

        private void FiltersDataGridView_CellLeave(object sender, DataGridViewCellEventArgs e)
        {
            if (e.ColumnIndex == FilterTypeColumn.Index && FiltersDataGridView.EditingControl != null)
            {
                ComboBox childComboBox = FiltersDataGridView.EditingControl as ComboBox;
                CheckedComboBoxControl childCheckComboBox = FiltersDataGridView.EditingControl as CheckedComboBoxControl;

                // Put this before the ComboBox check because it derives from ComboBox
                if (childCheckComboBox != null)
                {
                    childCheckComboBox.DropDownClosed -= new EventHandler(FiltersDataGridView_DropDownClosed);
                }
                else if (childComboBox != null)
                {
                    childComboBox.SelectedIndexChanged -= new EventHandler(FiltersDataGridView_ComboBoxSelectedIndexChanged);
                }
            }
        }

        void FiltersDataGridView_DropDownClosed(object sender, EventArgs e)
        {
            ZoneCategoriesDataGridViewEditingControl editingControl = sender as ZoneCategoriesDataGridViewEditingControl;
            List<INamedZone> newSelection = new List<INamedZone>();
            Filter currentFilter = Filters.GetFilter(FiltersDataGridView.CurrentCell.RowIndex);

            if (currentFilter.CriteriaFacade != null)
            {
                foreach (NamedZoneCheckedComboBoxWrapper wrapper in editingControl.CheckedItems)
                {
                    newSelection.Add(wrapper.Zone);
                }
                currentFilter.SetSelectedZones(newSelection);

                FiltersDataGridView.CommitEdit(DataGridViewDataErrorContexts.Commit);
            }

            // Remove focus from the current cell.  For an unknown reason when a CheckBoxComboBox had the focus,
            //  the main window was minimized after closing the save template dialog
            if (FiltersDataGridView.CurrentCell != null)
            {
                FiltersDataGridView.CurrentCell = FiltersDataGridView.Rows[FiltersDataGridView.CurrentCell.RowIndex].Cells[2];
            }
        }

        private void FiltersDataGridView_CellContentClick(object sender, DataGridViewCellEventArgs e)
        {
            if (e.ColumnIndex == RemoveFilterColumn.Index && e.RowIndex != -1)
            {
                bool removedLastRow = e.RowIndex == FiltersDataGridView.RowCount - 1;

                Filters.RemoveFilter(e.RowIndex);
                CheckIfEmptyRowRequired();
            }
        }

        private void FiltersDataGridView_CellValidated(object sender, DataGridViewCellEventArgs e)
        {
            if (e.ColumnIndex == FilterTypeColumn.Index)
            {
                // For an unknown reason the value is changed (probably by the combo box)
                //  and it becomes an invalid type.  So make sure to reset it correctly
                Filter currentFilter = Filters.GetFilter(e.RowIndex);
                DataGridViewComboBoxCell typeCell = FiltersDataGridView.Rows[e.RowIndex].Cells[FilterTypeColumn.Index] as DataGridViewComboBoxCell;

                if (currentFilter.CriteriaFacade != null)
                {
                    typeCell.Value = GetMatchingCriteria(typeCell, currentFilter.CriteriaFacade);
                }
                else
                {
                    typeCell.Value = null;
                }
            }
        }

        private void FiltersDataGridView_ComboBoxSelectedIndexChanged(object sender, EventArgs e)
        {
            ComboBox comboBox = sender as ComboBox;

            if (comboBox.SelectedIndex != -1 &&
                FiltersDataGridView.CurrentCell.ColumnIndex == FilterTypeColumn.Index)
            {
                Filter modifiedFilter = Filters.GetFilter(FiltersDataGridView.CurrentCell.RowIndex);
                FilterCriteriaFacade criteria = comboBox.SelectedItem as FilterCriteriaFacade;
                IFilterCriteria newCriteria = criteria.OnCriteriaSelected(modifiedFilter.CriteriaFacade);

                if (newCriteria != null &&
                    !newCriteria.Equals(modifiedFilter.CriteriaFacade))
                {
                    modifiedFilter.Criteria = newCriteria;
                }
                else if(newCriteria == null ||
                        !newCriteria.Equals(modifiedFilter.CriteriaFacade))
                {
                    modifiedFilter.Criteria = null;
                }
            }
        }

        protected void TriggerColumnWidthChanged(object sender, DataGridViewColumnEventArgs e)
        {
            if (ColumnWidthChanged != null)
            {
                ColumnWidthChanged(sender, e);
            }
        }

        public void ThemeChanged(ITheme visualTheme)
        {
            FiltersDataGridView.ColumnHeadersDefaultCellStyle.BackColor = visualTheme.SubHeader;
        }

        public void UICultureChanged(CultureInfo culture)
        {
            FilterTypeColumn.HeaderText = PluginView.GetLocalizedString("FilterTypeText");
            ItemColumn.HeaderText = PluginView.GetLocalizedString("ItemText");

            RefreshDataGridViewFromFilters(Filters);
        }

        void SetupAvailableCriterias()
        {
            FilterTypeColumn.Items.Clear();

            if (FilterCriteriaController.Instance.AvailableCriterias != null)
            {
                foreach (IFilterCriteria criteria in FilterCriteriaController.Instance.AvailableCriterias)
                {
                    if (IsTemplateFilterList &&
                        (criteria.IsTemplateOnly || !criteria.IsMainViewOnly))
                    {
                        FilterTypeColumn.Items.Add(criteria);
                    }
                    else if (!IsTemplateFilterList &&
                            (criteria.IsMainViewOnly || !criteria.IsTemplateOnly))
                    {
                        FilterTypeColumn.Items.Add(criteria);
                    }
                }
            }
        }

        private void RefreshDataGridViewFromFilters(FilterList filterList)
        {
            if (filterList != null)
            {
                for (int i = 0; i < filterList.GetFilterCount(); ++i)
                {
                    Filter currentFilter = filterList.GetFilter(i);
                    int rowIndex = i;

                    if (rowIndex >= FiltersDataGridView.Rows.Count)
                    {
                        rowIndex = FiltersDataGridView.Rows.Add();
                    }

                    DataGridViewComboBoxCell typeCell = FiltersDataGridView.Rows[rowIndex].Cells[FilterTypeColumn.Index] as DataGridViewComboBoxCell;
                    ZoneCategoriesDataGridViewCell zonesCell = FiltersDataGridView.Rows[rowIndex].Cells[ItemColumn.Index] as ZoneCategoriesDataGridViewCell;

                    // Update the row with the current data
                    if (currentFilter.CriteriaFacade != null)
                    {
                        // Type
                        typeCell.Value = GetMatchingCriteria(typeCell, currentFilter.CriteriaFacade);

                        // Zones
                        if (currentFilter.CriteriaFacade is TemplateFilterCriteria)
                        {
                            List<INamedZone> filteredTemplateNamedZones = new List<INamedZone>();

                            foreach (TemplateNamedZone templateZone in currentFilter.CriteriaFacade.ConcreteNamedZones)
                            {
                                if ((IsTemplateFilterList || !templateZone.Template.ShowOnlyInSettings) && 
                                    templateZone.Template != m_RestrictedTemplate &&
                                    !templateZone.Template.Filters.ContainsTemplate(m_RestrictedTemplate))
                                {
                                    filteredTemplateNamedZones.Add(templateZone);
                                }
                            }

                            zonesCell.DataSource = filteredTemplateNamedZones;
                        }
                        else
                        {
                            zonesCell.DataSource = currentFilter.CriteriaFacade.ConcreteNamedZones;
                        }

                        // Selection
                        zonesCell.Value = currentFilter.Zones;
                    }
                    else
                    {
                        typeCell.Value = null;
                        zonesCell.DataSource = null;
                        zonesCell.Value = null;
                    }
                }

                // Remove excess rows
                while (filterList.GetFilterCount() < FiltersDataGridView.Rows.Count)
                {
                    FiltersDataGridView.Rows.RemoveAt(FiltersDataGridView.Rows.Count - 1);
                }

                FiltersDataGridView.Invalidate();
            }
        }

        private IFilterCriteria GetMatchingCriteria(DataGridViewComboBoxCell typeCell, IFilterCriteria criteria)
        {
            foreach (IFilterCriteria filterCriteria in typeCell.Items)
            {
                if (filterCriteria.ReferenceId == criteria.ReferenceId)
                {
                    return filterCriteria;
                }
            }

            return null;
        }

        private void CheckIfEmptyRowRequired()
        {
            if (Filters != null)
            {
                if (Filters.GetFilterCount() > 0)
                {
                    Filter lastFilter = Filters.GetFilter(Filters.GetFilterCount() - 1);

                    Debug.Assert(lastFilter != null);

                    if (lastFilter.IsValid)
                    {
                        Filters.AddFilter(new Filter());
                    }
                }
                else
                {
                    Filters.AddFilter(new Filter());
                }
            }
        }

        [Browsable(false), ReadOnly(true)]
        public FilterList Filters
        {
            get { return m_CurrentFilters; }
            set
            {
                if (m_CurrentFilters != value)
                {
                    if (Filters != null)
                    {
                        Filters.FilterChanged -= new FilterList.FilterChangedEventHandler(OnFilterChanged);
                        Filters.FilterListChanged -= new FilterList.FilterListChangedEventHandler(OnFilterListChanged);
                    }

                    m_CurrentFilters = value;

                    if (Filters != null)
                    {
                        Filters.FilterChanged += new FilterList.FilterChangedEventHandler(OnFilterChanged);
                        Filters.FilterListChanged += new FilterList.FilterListChangedEventHandler(OnFilterListChanged);
                    }

                    CheckIfEmptyRowRequired();
                }

                RefreshDataGridViewFromFilters(value);
            }
        }

        public int CriteriaTypesColumnWidth
        {
            get { return m_CriteriaTypesColumnWidth; }
            set
            {
                if (value != CriteriaTypesColumnWidth)
                {
                    m_CriteriaTypesColumnWidth = value;
                    FilterTypeColumn.Width = value;

                    TriggerColumnWidthChanged(this, new DataGridViewColumnEventArgs(FilterTypeColumn));
                }
            }
        }

        public int NamedZonesColumnWidth
        {
            get { return m_NamedZonesColumnWidth; }
            set
            {
                if (value != NamedZonesColumnWidth)
                {
                    m_NamedZonesColumnWidth = value;
                    ItemColumn.Width = value;

                    TriggerColumnWidthChanged(this, new DataGridViewColumnEventArgs(ItemColumn));
                }
            }
        }

        public Template RestrictedTemplate
        {
            set
            {
                m_RestrictedTemplate = value;
            }
        }

        public bool IsTemplateFilterList
        {
            get { return m_IsTemplateFilterList; }
            set
            {
                if (IsTemplateFilterList != value)
                {
                    m_IsTemplateFilterList = value;

                    SetupAvailableCriterias();
                }
            }
        }

        [CategoryAttribute("Action")]
        public event DataGridViewColumnEventHandler ColumnWidthChanged;
       

        private FilterList m_CurrentFilters = null;
        private Template m_RestrictedTemplate = null;
        private int m_CriteriaTypesColumnWidth = 150;
        private int m_NamedZonesColumnWidth = 200;
        private bool m_IsTemplateFilterList = false;
    }
}
